package com.kgc.scd.service.impl;

import com.kgc.scd.config.WechatAuthConfig;
import com.kgc.scd.service.WechatAuthService;
import com.kgc.scd.util.HttpClient4Util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * Created On : 2022/10/28.
 * <p>
 * Author : 刘慧枫
 * <p>
 * Description: 微信授权业务接口实现类
 */
@Slf4j
@Service
public class WechatAuthServiceImpl implements WechatAuthService {
    @Autowired
    private WechatAuthConfig wechatAuthConfig;

    @Override
    public String generateWechatAuthCodeUrl() {

        //微信官方引导用户打开授权页面，获取code的完整请求示例

        //https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
        //若提示“该链接无法访问”，请检查参数是否填写错误，是否拥有 scope 参数对应的授权作用域权限。
        //尤其注意：由于授权操作安全等级较高，所以在发起授权请求时，微信会对授权链接做正则强匹配校验，如果链接的参数顺序不对，授权页面将无法正常访问

        //生成请求微信官方，获取用户code的完整地址
        StringBuilder wechatAuthCodeUrl = new StringBuilder(wechatAuthConfig.getCodeUri());
        wechatAuthCodeUrl.append("?appid=").append(wechatAuthConfig.getAppId())
                .append("&redirect_uri=").append(wechatAuthConfig.getRedirectUri())
                .append("&response_type=code")
                .append("&scope=").append("snsapi_userinfo")
                .append("&state=").append("wyyx_wechat_auth")
                .append("#wechat_redirect");
        return String.valueOf(wechatAuthCodeUrl);
    }

    @Override
    public String getAccessTokenFromWechatUseCode(String wechatAuthCode) {
        // 尤其注意：由于公众号的 secret 和获取到的access_token安全级别都非常高，必须只保存在服务器，不允许传给客户端。
        // 请求方法:获取 code 后，请求以下链接获取access_token：
        // https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

        // 封装根据code，请求微信官方获取access_token的完整地址
        StringBuilder accessTokenUrl = new StringBuilder(wechatAuthConfig.getAccessTokenUri());
        accessTokenUrl.append("?appid=").append(wechatAuthConfig.getAppId())
                .append("&secret=").append(wechatAuthConfig.getAppSecret())
                .append("&code=").append(wechatAuthCode)
                .append("&grant_type=authorization_code");

        log.info("------ 根据code，请求微信官方获取access_token的完整地址:{} ------", accessTokenUrl.toString());

        // 根据code，请求微信官方获取access_token，返回结果是同步返回的，不再是异步回调
        // 请求是服务器内部发起的，也就是说：在程序中，要根据上面完整的请求地址，主动发送请求到微信官方，接口同步会返回一个json格式的字符串结果，程序内要解析获取的结果

        // 程序内主动发起http请求，获取access_token
        return HttpClient4Util.getResponse4GetAsString(accessTokenUrl.toString(), "utf-8");
    }

    @Override
    public String getUserInfoFromWechatUseAccessToken(String accessToken, String openId) {

        // 如果网页授权作用域为snsapi_userinfo，则此时开发者可以通过access_token和 openid 拉取用户信息了。
        // http：GET（请使用 https 协议）：
        // https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

        // 封装根据accessToken和openId，请求微信官方获取用户信息详情地址
        StringBuilder userInfoUrl = new StringBuilder(wechatAuthConfig.getUserInfoUri());
        userInfoUrl.append("?access_token=").append(accessToken)
                .append("&openid=").append(openId)
                .append("&lang=zh_CN");
        log.info("------ 根据access_token，请求微信官方获取userinfo的完整地址:{} ------", userInfoUrl.toString());

        // 程序内主动发起http请求，获取用户详情
        return HttpClient4Util.getResponse4GetAsString(userInfoUrl.toString(), "utf-8");
    }

    @Override
    public boolean testAccessToken(String accessToken, String openId) {
        //附：检验授权凭证（access_token）是否有效
        //http：GET（请使用 https 协议）：
        //https://api.weixin.qq.com/sns/auth?access_token=ACCESS_TOKEN&openid=OPENID

        StringBuilder testAccessTokenUrl = new StringBuilder((wechatAuthConfig.getAccessTokenUri()));
        testAccessTokenUrl.append("?access_token").append(accessToken)
                .append("&openid=").append(openId);
        log.info("------ 根据code，请求微信官方获取access_token的完整地址:{} ------", testAccessTokenUrl.toString());

        // 程序内主动发起http请求，获取用户详情
        if (HttpClient4Util.getResponse4GetAsString(testAccessTokenUrl.toString(), "utf-8") != null){
            return true;
        }
        return false;
    }
}
